#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from properties import *
from exception import *


class Maze:

    def __init__(self, n):
        """
        初始化迷宫
        :param n: 迷宫边长
        """
        self.current_node = [0, 0]
        self.n = n
        matrix = []
        for i in range(0, self.n):
            row = []
            for j in range(0, self.n):
                if i == 0 and j == 0:
                    row.append(Property(i, j, "起点", True))
                elif i == n - 1 and j == n - 1:
                    row.append(Property(i, j, "终点"))
                elif i < 3 and j < 3:
                    row.append(Property.make_new_property(i, j))
                else:
                    row.append(Property(i, j, "迷雾"))
            matrix.append(row)
        # matrix = [
        #     [Property(0, 0, "起点"), Property(0, 1, "路径"), Property(0, 2, "路径"), Property(0, 3, "迷雾"), Property(0, 4, "迷雾"), Property(0, 5, "迷雾")],
        #     [Property(1, 0, "路径"), Property(1, 1, "障碍"), Property(1, 2, "宝箱"), Property(1, 3, "迷雾"), Property(1, 4, "迷雾"), Property(1, 5, "迷雾")],
        #     [Property(2, 0, "路径"), Property(2, 1, "路径"), Property(2, 2, "路径"), Property(2, 3, "迷雾"), Property(2, 4, "迷雾"), Property(2, 5, "迷雾")],
        #     [Property(3, 0, "迷雾"), Property(3, 1, "迷雾"), Property(3, 2, "迷雾"), Property(3, 3, "迷雾"), Property(3, 4, "迷雾"), Property(3, 5, "迷雾")],
        #     [Property(4, 0, "迷雾"), Property(4, 1, "迷雾"), Property(4, 2, "迷雾"), Property(4, 3, "迷雾"), Property(4, 4, "迷雾"), Property(4, 5, "迷雾")],
        #     [Property(5, 0, "迷雾"), Property(5, 1, "迷雾"), Property(5, 2, "迷雾"), Property(5, 3, "迷雾"), Property(5, 4, "迷雾"), Property(5, 5, "迷雾")],
        # ]
        self.matrix = matrix

    def serialize(self):
        matrix = []
        for row in self.matrix:
            line = []
            for node in row:
                line.append({
                    "x": node.x,
                    "y": node.y,
                    "typ": node.typ,
                    "walked": node.walked,
                })
            matrix.append(line)
        return {
            "n": self.n,
            "current_node": self.current_node,
            "matrix": matrix
        }

    def deserialize(self, maze):
        self.n = maze["n"]
        self.current_node = maze["current_node"]
        result = []
        for row in maze["matrix"]:
            line = []
            for node in row:
                line.append(Property(
                    node['x'],
                    node['y'],
                    node['typ'],
                    node['walked'],
                ))
            result.append(line)
        self.matrix = result
        return self

    def __str__(self):
        result = ''
        for row in self.matrix:
            for pro in row:
                result += str(pro)
                result += ' | '
            result += '\n'
        return result

    def get_node_next_to(self, node):
        """
        获取一个节点相邻（正前，正后，正左，正右）的四个节点
        :param node: tuple(x, y)
        :return: list(tuple(x, y), ...)
        """
        try:
            x, y = node[0], node[1]
            node = self.matrix[x][y]
        except IndexError:
            raise PointCoordinateError(node)

        if 0 < x < self.n - 1 and 0 < y < self.n - 1:
            return [[x - 1, y], [x, y - 1], [x + 1, y], [x, y + 1]]
        elif x == 0 and 0 < y < self.n - 1:
            return [[x, y - 1], [x + 1, y], [x, y + 1]]
        elif x == self.n - 1 and 0 < y < self.n - 1:
            return [[x - 1, y], [x, y - 1], [x, y + 1]]
        elif 0 < x < self.n - 1 and y == 0:
            return [[x - 1, y], [x + 1, y], [x, y + 1]]
        elif 0 < x < self.n - 1 and y == self.n - 1:
            return [[x - 1, y], [x, y - 1], [x + 1, y]]
        elif x == 0 and y == 0:
            return [[x, y + 1], [x + 1, y]]
        elif x == 0 and y == self.n - 1:
            return [[x, y - 1], [x + 1, y]]
        elif x == self.n - 1 and y == 0:
            return [[x - 1, y], [x, y + 1]]
        elif x == self.n - 1 and y == self.n - 1:
            return [[x - 1, y], [x, y - 1]]
        else:
            raise PointCoordinateError(node)

    def if_walk(self, path):
        """
        按照path遍历迷宫的点，查看是否可以走通
        :param path: list(tuple(x, y), ...)
        :return: Bool type
        """
        # 取出最后一个点，遍历之前所有的点，只要有任何一个点不在[起点, 终点, 路径]中，则返回False；
        # 并判断遍历的当前点是否在路点的上一个节点的相邻点上，不在则raise；最后一个点如果是 障碍，返回False
        if len(path) <= 0:
            raise WayPointError(path)
        else:
            last_position = path[-1]
            try:
                node = self.matrix[last_position[0]][last_position[1]]
                if node.typ == "障碍":
                    return False
            except IndexError:
                raise PointCoordinateError(last_position)
            _path = path[0: -1]
            previous_node = None
            for position in _path:
                try:
                    node = self.matrix[position[0]][position[1]]
                except IndexError:
                    raise PointCoordinateError(position)
                if node.typ not in ["起点", "终点", "路径"]:
                    return False
                # 判断当前节点是否在上一个节点的相邻点上
                if previous_node is None:
                    previous_node = node
                else:
                    next_nodes = self.get_node_next_to([previous_node.x, previous_node.y])
                    if position not in next_nodes:
                        raise WayPointError(path)
                    else:
                        previous_node = node
            return True

    def walk(self, path):
        """
        按照path遍历迷宫的点
        :param path: list(tuple(x, y), ...)
        :return: 更新后的迷宫
        """
        for position in path:
            node = self.matrix[position[0]][position[1]]
            node.walked = True
            clear_result, explore_result = node.trigger(self.n)
            # 将clear_result列表中的所有迷雾点点亮，生成随机道具
            for r in clear_result:
                node = self.matrix[r[0]][r[1]]
                if node.typ in ["迷雾"]:
                    self.matrix[r[0]][r[1]] = Property.make_new_property(r[0], r[1])
            # 将explore_result列表中的所有爆破点爆破，生成路径或障碍
            for r in explore_result:
                node = self.matrix[r[0]][r[1]]
                if node.typ not in ["起点", "终点", "路径", "障碍"]:
                    self.matrix[r[0]][r[1]] = Property.explore_property(r[0], r[1])
        # 更新迷宫的当前立足点
        self.current_node = path[-1]
        # 更新完后刷新迷宫所有节点的walked重置为False
        for row in self.matrix:
            for node in row:
                node.walked = False
        return self


if __name__ == '__main__':
    MAP = Maze(6)
    print(MAP.get_node_next_to([5, 0]))
